package com.doit.doc;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import javax.net.ssl.SSLException;

public class _02_人脸识别 {
    static String fileName ="C:\\Users\\34650\\Desktop\\jiang.jpg";
    public static void main(String[] args) throws Exception {


        //放我们识别得图片路径
        File file = new File(fileName);

        //将图片转变成字节数组加载在内存中
        byte[] buff = getBytesFromFile(file);

        //拼接服务请求参数
        String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();

        //需要分析得图片内容
        byteMap.put("image_file", buff);

        //这个key和secret需要去网站上注册才有
        map.put("api_key", "xh_tRR6MnMQK3kFaKEPBkVHBveItL-nM");
        map.put("api_secret", "0WOqCYcJBKD2sDmx8T6ZCxVOYkpYiH5_");

        //识别图片，返回图片检测得信息  这个可以不屑
//        map.put("return_landmark", "1");

        //获取结果人脸识别得具体内容，如下写了性别，年龄，微笑指数，是否带眼镜，情绪，颜值，健康状态等
        map.put("return_attributes", "gender,age,smiling,glass,emotion,beauty,skinstatus");

        try {
            byte[] res = post(url, map, byteMap);
            String str = new String(res);
            parseResponse(str);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * {
     * "request_id":"1705676012,c6c2388a-2ea5-41ab-b859-457a333f3bf4",
     * "time_used":433,
     * "faces":[
     * {
     * "face_token":"f6deadc15cf4dee013f31fb1cf1873c6",
     * "face_rectangle":{
     * "top":504,
     * "left":464,
     * "width":64,
     * "height":64
     * },
     * "attributes":{
     * "gender":{
     * "value":"Male"
     * },
     * "age":{
     * "value":29
     * },
     * "smile":{
     * "value":57.299,
     * "threshold":50
     * },
     * "emotion":{
     * "anger":0,
     * "disgust":0.004,
     * "fear":0.001,
     * "happiness":0.209,
     * "neutral":99.787,
     * "sadness":0,
     * "surprise":0
     * },
     * "beauty":{
     * "male_score":58.912,
     * "female_score":55.743
     * },
     * "skinstatus":{
     * "health":31.793,
     * "stain":2.865,
     * "dark_circle":1.868,
     * "acne":3.423
     * }
     * }
     * }
     * ],
     * "image_id":"d6H6WZKBRtTRBZVYdRWDGA==",
     * "face_num":1
     * }
     */
    //自己写一个方法来解析出来返回的结果，也就是json串
    private static void parseResponse(String json) {
        JSONObject jsonObject = JSON.parseObject(json);
        JSONArray faces = jsonObject.getJSONArray("faces");
        JSONObject face = faces.getJSONObject(0);
        JSONObject attr = face.getJSONObject("attributes");

        //获取性别
        String gender = attr.getJSONObject("gender").getString("value");

        //获取年龄
        int age = attr.getJSONObject("age").getIntValue("value");

        //获取是否笑容
        float smale_score = attr.getJSONObject("smile").getFloatValue("value");//笑容情况
        float smale_threshold = attr.getJSONObject("smile").getFloatValue("threshold");//阈值


        //获取面部情绪情况
        float emotion_anger = attr.getJSONObject("emotion").getFloatValue("anger");//愤怒
        float emotion_disgust = attr.getJSONObject("emotion").getFloatValue("disgust");//厌恶
        float emotion_fear = attr.getJSONObject("emotion").getFloatValue("fear");//恐惧
        float emotion_happiness = attr.getJSONObject("emotion").getFloatValue("happiness");//高兴
        float emotion_neutral = attr.getJSONObject("emotion").getFloatValue("neutral");//平静
        float emotion_sadness = attr.getJSONObject("emotion").getFloatValue("sadness");//伤心
        float emotion_surprise = attr.getJSONObject("emotion").getFloatValue("surprise");//惊讶

        //写一个方法，确定当前情绪状况
        String emotion_res = checkEmotion(emotion_anger, emotion_disgust, emotion_fear, emotion_happiness, emotion_neutral, emotion_sadness, emotion_surprise);


        //获取颜值
        float beauty_male_score = attr.getJSONObject("beauty").getFloatValue("male_score");
        float beauty_female_score = attr.getJSONObject("beauty").getFloatValue("female_score");


        //获取健康状态
        float skinstatus_health = attr.getJSONObject("skinstatus").getFloatValue("health");//健康
        float skinstatus_stain = attr.getJSONObject("skinstatus").getFloatValue("stain");//色斑
        float skinstatus_dark_circle = attr.getJSONObject("skinstatus").getFloatValue("dark_circle");//青春痘
        float skinstatus_acne = attr.getJSONObject("skinstatus").getFloatValue("acne");//黑眼圈
        //写一个方法获取健康状态
        String skinStatus = checkSkinStatus(skinstatus_health, skinstatus_stain, skinstatus_dark_circle, skinstatus_acne);

        String[] arr = fileName.split("\\\\");
        String fileName1 = arr[arr.length - 1];
        String[] arr2 = fileName1.split("\\.");
        System.out.println("识别"+arr2[0]+"的艳照后，人脸识别结果如下：");
        System.out.println("性别：" + (gender.equals("Male") ? "男性" : "女性"));
        System.out.println("年龄：" + age);
        System.out.println("笑容情况：" + (smale_score > smale_threshold ? "微笑" : "没有微笑"));
        System.out.println("情绪识别结果：" + emotion_res);
        System.out.println("颜值获取结果：" + (gender.equals("Male") ? beauty_male_score : beauty_female_score) + "==> 满分100分哦");
        System.out.println("面部特征识别结果：" + skinStatus);
    }

    private static String checkSkinStatus(float skinstatus_health, float skinstatus_stain, float skinstatus_dark_circle, float skinstatus_acne) {
        float max1 = Math.max(skinstatus_health, skinstatus_stain);
        float max2 = Math.max(max1, skinstatus_dark_circle);
        float res = Math.max(max2, skinstatus_acne);
        if (res == skinstatus_health) {
            return "健康";
        } else if (res == skinstatus_stain) {
            return "色斑";
        } else if (res == skinstatus_dark_circle) {
            return "青春痘";
        } else {
            return "黑眼圈";
        }
    }

    private static String checkEmotion(float emotion_anger, float emotion_disgust, float emotion_fear, float emotion_happiness, float emotion_neutral, float emotion_sadness, float emotion_surprise) {
        float max1 = Math.max(emotion_anger, emotion_disgust);
        float max2 = Math.max(max1, emotion_fear);
        float max3 = Math.max(max2, emotion_happiness);
        float max4 = Math.max(max3, emotion_neutral);
        float max5 = Math.max(max4, emotion_sadness);
        float res = Math.max(max5, emotion_surprise);
        if (res == emotion_anger) {
            return "愤怒";
        } else if (res == emotion_disgust) {
            return "厌恶";
        } else if (res == emotion_fear) {
            return "恐惧";
        } else if (res == emotion_happiness) {
            return "高兴";
        } else if (res == emotion_neutral) {
            return "平静";
        } else if (res == emotion_sadness) {
            return "伤心";
        } else {
            return "惊讶";
        }
    }


    private final static int CONNECT_TIME_OUT = 30000;
    private final static int READ_OUT_TIME = 50000;
    private static String boundaryString = getBoundary();

    protected static byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
        HttpURLConnection conne;

        URL url1 = new URL(url);
        conne = (HttpURLConnection) url1.openConnection();
        conne.setDoOutput(true);
        conne.setUseCaches(false);
        conne.setRequestMethod("POST");
        conne.setConnectTimeout(CONNECT_TIME_OUT);
        conne.setReadTimeout(READ_OUT_TIME);
        conne.setRequestProperty("accept", "*/*");
        conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
        conne.setRequestProperty("connection", "Keep-Alive");
        conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
        DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry) iter.next();
            String key = entry.getKey();
            String value = entry.getValue();
            obos.writeBytes("--" + boundaryString + "\r\n");
            obos.writeBytes("Content-Disposition: form-data; name=\"" + key
                    + "\"\r\n");
            obos.writeBytes("\r\n");
            obos.writeBytes(value + "\r\n");
        }
        if (fileMap != null && fileMap.size() > 0) {
            Iterator fileIter = fileMap.entrySet().iterator();
            while (fileIter.hasNext()) {
                Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
                obos.writeBytes("--" + boundaryString + "\r\n");
                obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
                        + "\"; filename=\"" + encode(" ") + "\"\r\n");
                obos.writeBytes("\r\n");
                obos.write(fileEntry.getValue());
                obos.writeBytes("\r\n");
            }
        }
        obos.writeBytes("--" + boundaryString + "--" + "\r\n");
        obos.writeBytes("\r\n");
        obos.flush();
        obos.close();
        InputStream ins = null;
        int code = conne.getResponseCode();
        try {
            if (code == 200) {
                ins = conne.getInputStream();
            } else {
                ins = conne.getErrorStream();
            }
        } catch (SSLException e) {
            e.printStackTrace();
            return new byte[0];
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int len;
        while ((len = ins.read(buff)) != -1) {
            baos.write(buff, 0, len);
        }
        byte[] bytes = baos.toByteArray();
        ins.close();
        return bytes;
    }

    private static String getBoundary() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 32; ++i) {
            sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
        }
        return sb.toString();
    }

    private static String encode(String value) throws Exception {
        return URLEncoder.encode(value, "UTF-8");
    }

    public static byte[] getBytesFromFile(File f) {
        if (f == null) {
            return null;
        }
        try {
            FileInputStream stream = new FileInputStream(f);
            ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
            byte[] b = new byte[1000];
            int n;
            while ((n = stream.read(b)) != -1)
                out.write(b, 0, n);
            stream.close();
            out.close();
            return out.toByteArray();
        } catch (IOException e) {
        }
        return null;
    }
}


